# -*- coding: utf-8 -*-
# Import Odoo models and fields


from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError


class SForecastOrder(models.Model):
    _name = 's.forecast.order'  # Technical name of the model
    _description = 'Forecast Order'  # Description of the model
    _inherit = ['mail.thread', 'mail.activity.mixin']  # Inherit mail and activity mixins for communication features

    # Field definitions
    name = fields.Char(
        string='Forecast Order Reference',  # Forecast order number
        required=True,
        copy=False,
        readonly=True,
        default=lambda self: _('New')  # Default to 'New', will be filled by sequence
    )
    customer_id = fields.Many2one(
        'res.partner',
        string='Customer',  # Customer
        required=True,
        tracking=True  # Track field changes
    )
    currency = fields.Many2one(
        'res.currency',
        string='Currency',
        related='customer_id.currency_id',  # Related to customer's currency
    )
    forecast_date = fields.Date(
        string='Forecast Date',  # Forecast date
        required=True,
        default=fields.Date.today(),  # Default to today's date
        tracking=True
    )
    state = fields.Selection([
        ('draft', 'Draft'),
        ('marketing_confirmed', 'Marketing'),  # Marketing Confirmed
        ('engineering_confirmed', 'Engineering'),  # Engineering Confirmed
        ('material_calculated', 'Materials Calculated'),  # Materials Calculated
        ('requisition_generated', 'Requisition Generated'),  # Requisition Generated
        ('done', 'Done'),  # Done
        ('cancel', 'Cancelled'),  # Cancelled
    ], string='State', default='draft', tracking=True)  # Default state is Draft

    forecast_order_line_ids = fields.One2many(
        's.forecast.order.line',  # Updated to s.forecast.order.line
        'forecast_order_id',
        string='Forecast Order Lines',  # Forecast order lines
        copy=True
    )
    responsible_id = fields.Many2one(
        'res.users',
        string='Responsible',  # Responsible user
        default=lambda self: self.env.user,  # Default to the current user
        tracking=True
    )
    # NEW: Material summary lines
    material_summary_ids = fields.One2many(
        's.forecast.material.summary',
        'forecast_order_id',
        string='Material Summary',
        readonly=True  # This table is calculated, not directly editable
    )

    # purchase_requisition_ids = fields.One2many(
    #     'purchase.requisition',
    #     's_forecast_order_id',
    #     string='Purchase Requisitions',
    #     readonly=True
    # )
    # NEW: Computed field to check if all materials are procured
    all_materials_procured = fields.Boolean(
        string='All Materials Procured',
        compute='_compute_all_materials_procured',
        store=True  # Store the computed result
    )

    note = fields.Text('Note', help="Additional notes for this forecast order")  # Additional notes for this forecast order
    sale_order_count = fields.Integer(string='Sale Order Count', compute='_compute_sale_order_count')  # Sale order count
    so_use_updated = fields.Boolean(string='SO Use Updated', compute='_compute_so_use_updated', store=True)

    @api.depends('forecast_order_line_ids.so_use_updated')
    def _compute_so_use_updated(self):
        for order in self:
            order.so_use_updated = all(
                line.so_use_updated for line in order.forecast_order_line_ids
            )

    @api.depends('material_summary_ids.remaining_purchase_quantity')
    def _compute_all_materials_procured(self):
        for order in self:
            order.all_materials_procured = all(
                summary_line.remaining_purchase_quantity <= 0
                for summary_line in order.material_summary_ids
            )

    def return_marketing_confirmed(self):
        self.state = 'marketing_confirmed'

    def marketing_confirmed(self):
        self.state = 'engineering_confirmed'

    # Button action: Submit Forecast (Marketing Department)
    def action_submit_forecast(self):
        # Check if there are any forecast order lines
        if not self.forecast_order_line_ids:
            raise UserError(_("Please add at least one forecast order line."))  # Please add at least one forecast order line.
        for rec in self.forecast_order_line_ids:
            rec._onchange_engineering_confirmed_product_id()
        self.state = 'engineering_confirmed'
        self.name = self.env['ir.sequence'].next_by_code('s.forecast.order.sequence')

    # Button action: Confirm Engineering (Engineering Department)
    def action_confirm_engineering(self):
        # Check if all forecast order lines have been processed (product confirmed or marked as new)
        for line in self.forecast_order_line_ids:
            if not line.engineering_confirmed_product_id:
                raise UserError(
                    _("Please confirm the product for all forecast order lines or mark them as new products."))  # Please confirm the product for all forecast order lines or mark them as new products.

            # If it's a new product and the engineer hasn't selected one, automatically create a new product
            if not line.engineering_confirmed_product_id:
                new_product = self.env['product.product'].create({
                    'name': line.market_forecast_product_name,
                    'type': 'product',  # Product type
                    'default_code': self.env['ir.sequence'].next_by_code('product.product') or _('NEW_PROD'),  # Automatically generate product code
                })
                line.engineering_confirmed_product_id = new_product.id
                self.env['mrp.bom'].create({
                    'product_tmpl_id': new_product.product_tmpl_id.id,
                    'type': 'normal',
                    'product_qty': 1.0,
                    'name': _('BOM for %s') % new_product.name,  # BOM name
                })
                line.message_post(body=_(
                    "Product record and empty BOM automatically created for new product '%s'.") % new_product.name)  # Product record and empty BOM automatically created for new product '%s'.

            if not line.material_line_ids:
                raise UserError(_("Please add material requirements for all forecast order lines."))
        self.write({'state': 'engineering_confirmed'})
        self.action_calculate_materials()  # Calculate materials immediately after confirmation

    # Button action: Calculate Materials (Any department, typically Engineering or Purchasing)
    def action_calculate_materials(self):
        for line in self.forecast_order_line_ids:
            line._update_material_lines()  # Update material requirements for each forecast order line
        self._update_material_summary()  # NEW: Update the summarized material requirements
        self.write({'state': 'material_calculated'})

    def _update_material_summary(self):
        self.ensure_one()
        summary_data = {}

        # Aggregate material requirements from all lines
        for line in self.forecast_order_line_ids:
            for material_line in line.material_line_ids:
                material_id = material_line.material_id.id
                if material_id not in summary_data:
                    summary_data[material_id] = {
                        'material_id': material_id,
                        'total_required_quantity': 0.0,
                        'procured_quantity': 0.0,  # Initialize procured quantity
                    }
                summary_data[material_id]['total_required_quantity'] += material_line.required_quantity

        # Update existing summary lines or create new ones
        existing_summary_lines = {sum_line.material_id.id: sum_line for sum_line in self.material_summary_ids}
        for material_id, data in summary_data.items():
            if material_id in existing_summary_lines:
                # Update existing summary line
                summary_line = existing_summary_lines[material_id]
                summary_line.write({
                    'total_required_quantity': data['total_required_quantity'],
                    # 'procured_quantity' is updated via related POs/receipts, not here
                })
            else:
                # Create new summary line
                self.env['s.forecast.material.summary'].create({
                    'forecast_order_id': self.id,
                    'material_id': data['material_id'],
                    'total_required_quantity': data['total_required_quantity'],
                    'procured_quantity': data['procured_quantity'],
                })

        # Remove summary lines for materials no longer needed
        materials_to_remove = set(existing_summary_lines.keys()) - set(summary_data.keys())
        for material_id in materials_to_remove:
            existing_summary_lines[material_id].unlink()

    def action_generate_purchase_requisition(self):
        self.ensure_one()
        if not self.material_summary_ids:
            raise UserError(_("No materials to generate requisitions for."))  # No materials to generate requisitions for.

        # Filter for materials that still need to be purchased
        materials_to_purchase = self.material_summary_ids.filtered(
            lambda s: s.remaining_purchase_quantity > 0
        )
        if not materials_to_purchase:
            raise UserError(_("All required materials have already been procured or are in stock."))  # All required materials have already been procured or are in stock.

        # Create a new Purchase Requisition
        requisition_vals = {
            'origin': self.name,
            's_forecast_order_id': self.id,  # Link to this forecast order
            # 'type_id': self.env.ref('purchase_requisition.type_purchase_requisition').id,  # Default type
            'applicant': self.env.user.id,
            'line_ids': [],
        }

        for summary_line in materials_to_purchase:
            requisition_vals['line_ids'].append((0, 0, {
                'product_id': summary_line.material_id.id,
                'product_qty': summary_line.remaining_purchase_quantity,
                'product_uom_id': summary_line.material_id.uom_id.id,
                's_forecast_material_summary_id': summary_line.id,  # Link to the summary line
            }))

        new_requisition = self.env['purchase.requisition'].create(requisition_vals)
        self.write({'state': 'requisition_generated'})
        return {
            'name': _('Purchase Requisition'),  # Purchase Requisition
            'type': 'ir.actions.act_window',
            'res_model': 'purchase.requisition',
            'view_mode': 'form',
            'res_id': new_requisition.id,
            'target': 'current',
        }

    # Button action: Mark as Done
    def action_done(self):
        # Check if all materials are procured before marking as done
        if not self.all_materials_procured:
            raise UserError(_("Cannot mark as done. Not all required materials have been procured."))  # Cannot mark as done. Not all required materials have been procured.
        self.write({'state': 'done'})

    # Button action: Cancel Order
    def action_cancel(self):
        self.write({'state': 'cancel'})

    # Button action: Set to Draft
    def action_set_to_draft(self):
        self.write({'state': 'draft'})

    def action_view_purchase_requisitions(self):
        self.ensure_one()
        action = self.env['ir.actions.act_window']._for_xml_id('purchase_requisition.action_purchase_requisition')
        action['domain'] = [('s_forecast_order_id', '=', self.id)]
        action['context'] = {'create': False}

    def place_order(self):
        """Placeholder method for placing the forecast order."""
        # Implement order placement logic here
        self.ensure_one()
        return {
            'name': 'Place Forecast Order(Replaced Order)',  # Place Forecast Order(Replaced Order)
            'res_model': 'sb.fo.place.order.wiz',
            'view_mode': 'form',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'context': {
                'default_fo_id': self.id
            }
        }

    def place_an_order(self):
        return {
            'name': _('Select Order type'),
            'type': 'ir.actions.act_window',
            'res_model': 'place.order.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                "order_type": "order_type"
            },
        }

    def _compute_sale_order_count(self):
        for order in self:
            sale_orders = self.env['sale.order'].search([('sb_fo_line_id.forecast_order_id', '=', order.id)])
            order.sale_order_count = len(sale_orders)

    def action_view_sale(self):
        sale_orders = self.env['sale.order'].search([('sb_fo_line_id.forecast_order_id', '=', self.id)])
        if len(sale_orders) == 1:
            return {
                'name': 'Sale Order',
                'type': 'ir.actions.act_window',
                'res_model': 'sale.order',
                'view_mode': 'form',
                'res_id': sale_orders.id,
                'target': 'current',
            }
        else:
            return {
                'name': 'Sale Orders',
                'type': 'ir.actions.act_window',
                'res_model': 'sale.order',
                'view_mode': 'tree,form',
                'target': 'current',
                'domain': [('id', 'in', sale_orders.ids)],
            }
